package br.com.JZSolution.domineduplex.rede;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.NoSuchAlgorithmException;

import br.com.JZSolution.domineduplex.DomineDuplex;
import br.com.JZSolution.domineduplex.modelo.Transferencia;
import br.com.JZSolution.domineduplex.rede.protocolo.ProtocoloRecebimento;
import br.com.JZSolution.domineduplex.utils.SecurityUtils;

public class Destinatario extends Thread{
	
	private Socket socketClient;
	private int totalBytesRecebidos = 0;
	private Transferencia transf = null;
	private boolean executando = false;
	
	public Destinatario(Socket socket) {
		this.socketClient = socket; 	
		start();
	}
	
	public void run() {
		OutputStream os = null;
		InputStream inputStream = null;
		FileOutputStream fos = null;
		String hashArquivo = null;
		try{
			System.out.println("Destinatario iniciado");
			executando = true;
			byte [] arrayLeitor = new byte[512];
			os = socketClient.getOutputStream();
			
			System.out.println("Envio solicitado");
			ProtocoloRecebimento protocolo = new ProtocoloRecebimento();
			
			File arquivoASerRecebido = protocolo.confirmarRecebimento(os, socketClient.getInputStream());
			
			if(arquivoASerRecebido == null){
				os.close();
				return;
			}

			
			long tamanhoArquivo = protocolo.getTamanhoDoArquivo();
			hashArquivo = protocolo.getHashArquivo();//para ser comparado
			
			System.out.println("Solicitação aceita!");
			
			int bytesRead = 0;
			inputStream = socketClient.getInputStream();
			fos = new FileOutputStream(arquivoASerRecebido);
			
			ativarContadorDeVelocidade();
			transf = new Transferencia(arquivoASerRecebido,tamanhoArquivo,"X","X");
			transf.setEstado(Transferencia.ATIVA);
			
			do{
				bytesRead = inputStream.read(arrayLeitor);
				if (bytesRead > 0){
					fos.write(arrayLeitor,0,bytesRead);
				
					totalBytesRecebidos += bytesRead;
					transf.atualizarInterface(totalBytesRecebidos);
				}	
			}while ( bytesRead != -1); 
			
		}catch (Exception e) {
			transf.setEstado(Transferencia.CANCELADA);
			e.printStackTrace();
		}finally{
			if(transf != null){
				DomineDuplex.getInstance().avisarFimDeTransferencia(transf);
				try {
					if(isIntegro(transf,hashArquivo)){
						transf.setEstado(Transferencia.CONCLUIDA_SUCESSO);
						System.out.println("Destinatario 75 = Concluída com êxito");
					}else{
						transf.setEstado(Transferencia.CONCLUIDA_FALHA);
						System.out.println("Destinatario 78 = Concluída com falha");
					}
				}catch (Exception e) {
					transf.setEstado(Transferencia.CONCLUIDA_FALHA);
				}	
			}	
			//Fechando o stream
			if(os != null)
				try{ os.close(); }catch (Exception e) {}
			if(inputStream != null)
				try{ inputStream.close(); }catch (Exception e) {}
			if(fos != null)
				try{ fos.close(); }catch (Exception e) {}
			if(socketClient != null)
				try{ socketClient.close(); }catch (Exception e) {}
			 
			executando = false;	
			if(transf != null)
				transf.setVelocidade(0);
			System.out.println("Destinatario Finalizado");
		}
	}

	private void ativarContadorDeVelocidade() {
		Thread t = new Thread(){
			public void run() {
				long temporizador = 0;
				final long sleep = 500;
				long ultimosBytes = 0;
				long inicioBytes = 0;
				
				while(executando){
					try{
						ultimosBytes = totalBytesRecebidos;
						if(temporizador == sleep * 10 || temporizador == 0){
							float velocidade = ultimosBytes - inicioBytes;
							velocidade = (velocidade / (sleep * 10));// KBps 
							//avisa a interface
							transf.setVelocidade(velocidade);

							inicioBytes = totalBytesRecebidos;
							temporizador = 0;
						}
						Thread.sleep(sleep);
						temporizador += sleep;
					}catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		};	
		t.start();
	}
	
	private boolean isIntegro(Transferencia transf, String hashRemente) throws NoSuchAlgorithmException, FileNotFoundException, IOException {
		if(SecurityUtils.gerarHashMd5(transf.getArquivo()).equals(hashRemente)){
			return true;
		}else{
			return false;
		}
	}
}
